home *** CD-ROM | disk | FTP | other *** search
- /*
- dshell v3
-
- ローカルメニュー (v3.33~)
- */
-
- #include "dsh.h"
-
-
- #define MINWIDTH 8 // メニュー最小桁幅
- #define MAXWIDTH 48 // メニュー最大桁幅
- #define MAXHEIGHT 12 // 一度に表示するメニュー項目の最大数 (越える場合はスクロール)
-
- typedef struct menuItem {
- struct menuItem *next;
- void *str; // メニュー項目文字列 (ただし, str[0] はフラグ)
- } MENUITEM;
-
- typedef struct menu {
- struct menu *prev;
- MENUITEM *head; // メニュー項目リスト
- void *id; // このメニューを定義したテキストのID
- } MENU;
-
- static MENU *menuHead;
- static int nItem; // メニュー項目の総数
- static int nMenu; // メニューの総数
-
-
- /*
- メニュー項目を追加する
- */
- int
- addMenuItem(void *id, const uchar *str)
- {
- MENU *menu = menuHead;
- MENUITEM *item, *itemP;
-
- item = malloc(sizeof(MENUITEM));
- if (item == NULL)
- return -1;
- if (menu == NULL || menu->id != id) {
- menu = malloc(sizeof(MENU));
- if (menu == NULL)
- return -1;
- menu->prev = menuHead;
- menu->head = item;
- menu->id = id;
- menuHead = menu;
- nMenu++;
- } else {
- for (itemP = menu->head; itemP->next != NULL; itemP = itemP->next)
- ;
- itemP->next = item;
- }
- item->next = NULL;
- item->str = str;
- nItem++;
-
- return 0;
- }
-
-
- /*
- 定義したテキストの閲覧終了時に対応するメニューがあれば解放する
- */
- void
- freeMenu(void *id)
- {
- MENU *menu = menuHead;
- MENUITEM *item, *itemP;
-
- if (menu == NULL || menu->id != id)
- return;
- menuHead = menu->prev;
- for (itemP = menu->head; itemP != NULL;) {
- item = itemP;
- itemP = itemP->next;
- free(item);
- nItem--;
- }
- free(menu);
- nMenu--;
- }
-
-
- static int
- getStrWidth(const uchar *str)
- {
- uchar *p = str;
- uchar c;
- int n = 1;
-
- while ((c = *p++) != '\0') {
- if (iskanji1(c)) {
- p++;
- if (c == 0x80 || c >= 0xf0)
- n++;
- }
- }
- return (p - str) - n;
- }
-
-
- static void
- drawMenu(int x, int y, uchar **items, int width, int n)
- {
- while (--n >= 0)
- B_PUTMES(3, x, y++, width - 1, (*items++) + 1);
- }
-
-
- /*
- メニュー選択 (下メニューバー中の MENU を右クリックでオープン)
- */
- void
- localMenu(int sx)
- {
- uchar **items;
- MENU *menu;
- MENUITEM *itemP;
- uchar *command;
- int n, len, width, height, base;
- int x0, y0, gx0, gy0, gwidth;
- uchar rollFlag = FALSE;
- uchar bar[1 + MAXWIDTH + 1]; // フラグ,───,0
- int mx, my, dx, dy, bl, br;
- int m, mm, et;
- uchar flag;
- struct TREVPTR trevBuf;
-
- // リスト表現された複数メニューを連結してポインタ配列を作る (ちょいダサ)
- if (nItem <= 0 || (items = malloc(sizeof(*items) * (nItem + nMenu))) == NULL) {
- wait_mb_off();
- return;
- }
- n = 0;
- width = MINWIDTH;
- for (menu = menuHead; menu != NULL;) {
- for (itemP = menu->head; itemP != NULL; itemP = itemP->next) {
- items[n++] = itemP->str;
- len = getStrWidth(itemP->str + 1);
- if (len > width)
- width = len;
- }
- menu = menu->prev;
- if (menu != NULL)
- items[n++] = bar;
- }
- items[n] = NULL;
- width = (width + 1) & -2;
- height = n;
- if (height > MAXHEIGHT) {
- height = MAXHEIGHT;
- rollFlag = TRUE;
- }
- if (nMenu > 1) {
- uchar *p = bar;
- int i;
-
- *p++ = 0;
- for (i = 0; i < width / 2; i++) {
- *p++ = (uchar)(L'─' >> 8);
- *p++ = (uchar)(L'─');
- }
- *p = '\0';
- }
- sx--;
- x0 = sx - 1;
- if (x0 + width + 2 > CWIDTH)
- x0 = CWIDTH - width - 2;
- y0 = 30 - height;
- B_COLOR(5);
- gx0 = (x0 << 3) - 4;
- gy0 = y0 << 4;
- gwidth = (width << 3) + 8;
- trevBuf.vram_page = 0;
- trevBuf.x = gx0;
- trevBuf.x1 = gwidth;
- trevBuf.y1 = 16;
- if (rollFlag) {
- y0--;
- gy0 -= 16;
- win_frame(x0 - 2, y0 - 2, x0 + width, 30, 0, sx);
- B_PUTMES(3, x0 + width / 2 - 1, y0 - 1, 2 - 1, "▲");
- B_PUTMES(3, x0 + width / 2 - 1, 29, 2 - 1, "▼");
- msarea(gx0, gy0 - 16 + 1, gx0 + gwidth - 1, 511);
- } else {
- win_frame(x0 - 2, y0 - 1, x0 + width, 30, 0, sx);
- msarea(gx0, gy0 + 1, gx0 + gwidth - 1, 511);
- }
- B_COLOR(3);
- base = 0;
- drawMenu(x0, y0, items + base, width, height);
- wait_mb_off();
- mm = -2;
- et = 0;
- flag = FALSE;
- for (;;) {
- p_time(0);
- dmspos(&mx, &my);
- if (my >= 30 * 16)
- m = -2;
- else
- m = (my - gy0 + 16) / 16 - 1;
- if (m != mm) {
- if (mm > -2) {
- trevBuf.y = gy0 + mm * 16;
- TXREV(&trevBuf);
- }
- if (m > -2) {
- if (m == -1 || m == MAXHEIGHT || items[base + m][0]) {
- trevBuf.y = gy0 + m * 16;
- trevBuf.vram_page = 0;
- TXREV(&trevBuf);
- } else {
- m = -2;
- }
- }
- mm = m;
- }
- dmsstat(&dx, &dy, &bl, &br);
- if (br) {
- m = -2;
- break;
- }
- if (bl) {
- int ontime = d_ontime();
- if (m == -1 && base > 0 && et < ontime) {
- base--;
- drawMenu(x0, y0, items + base, width, height);
- et = init_et(et ? ((B_SFTSNS() & 1) ? 0 : 5) : 40);
- } else if (m == MAXHEIGHT && base < n - MAXHEIGHT && et < ontime) {
- base++;
- drawMenu(x0, y0, items + base, width, height);
- et = init_et(et ? ((B_SFTSNS() & 1) ? 0 : 5) : 40);
- } else if (m >= 0 && m < MAXHEIGHT && items[base + m][0]) {
- break;
- }
- } else
- et = 0;
- }
- msarea(0, 0, GWIDTH - 1, 511);
- p_scr();
- command = NULL;
- if (m >= 0 && items[base + m][0]) {
- command = items[base + m] + 1;
- while (*command++ != '\0')
- ;
- }
- free(items);
- wait_mb_off();
- if (command != NULL) {
- dtype(command, TRUE);
- p_fukki();
- mouse(1);
- }
- }
-